using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
using System.Globalization;
using System.Runtime.InteropServices;
using System.Security.Permissions;
using System.Windows.Forms;
using Microsoft.VisualStudio;
using Microsoft.VisualStudio.OLE.Interop;
using Microsoft.VisualStudio.Shell;
using Microsoft.VisualStudio.Shell.Interop;
using Microsoft.VisualStudio.TextManager.Interop;
using Constants=Microsoft.VisualStudio.OLE.Interop.Constants;
using IOleServiceProvider = Microsoft.VisualStudio.OLE.Interop.IServiceProvider;
using IOleDataObject = Microsoft.VisualStudio.OLE.Interop.IDataObject;
using Wicresoft.Shell.Core;
using Wicresoft.Shell.Package.AppExp;
using System.IO;
using System.ComponentModel.Design;

namespace Wicresoft.Shell.Package.AppExp
{
    //[ToolboxItemFilter("System.Windows.Forms",ToolboxItemFilterType.Custom)]
    public sealed class DesignerPane : UserControl,
                                IOleCommandTarget,          //to enable objects and their containers to dispatch commands 
                                                            //to each other
                                IVsWindowPane,              //to fill up a window frame
                                IVsTextLinesEvents,         //to notifies clients of changes to the underlying text buffer
                                IVsDeferredDocView,          //to provide a document view whose actual view is retrieved after 
                                                            //the document data has been loaded and registered in the Running Document Table (RDT)
                                IVsToolboxUser
    {
        #region Fields

        private ServiceProvider vsServiceProvider;  // VS shell service provider
        IVsTextLines textLines;                     // TextBuffer object
        private uint cookie;                        // Tracking cookie used to Advise/Unadvise IVsTextLinesEvents events.
        private string fileName;                    // Determine alternate file name
        private bool isDirty;                       // Shows the status of changes of the text
        // Flag is true when we receiving a OnTextChange event for a user edit. 
        private bool updatingOnUserEdit;            
        // Flag is true when we receiving a OnTextLineChangeEvent from the TextBuffer.
        private bool updatingOnTextBufferLineChange;
        // Flag is true when we are asking the QueryEditQuerySave service if we can edit the file. 
        // It is used to avoid to have more than one request queued.
        private bool gettingCheckoutStatus;

        // Required designer variable.
        private Container components = null;

        private UmcDesignSurface designSurface;

        #endregion

        #region Constructors
        /// <summary>
        /// Private constructor.
        /// </summary>
        private DesignerPane()
        {
            PrivateInit(null, null);
        }

        /// <summary>
        /// Initializes a new instance of the EditorPane with specified parameter values.
        /// </summary>
        /// <param name="fileName">An absolute path for the file that will be edited.</param>
        /// <param name="textBuffer">The reference to the instance of TextBuffer object.</param>
        /// <exception cref="System.ArgumentNullException">textBuffer is a null reference.</exception>
        /// <exception cref="System.ArgumentNullException">fileName is a null reference.</exception>
        /// <exception cref="System.ArgumentException">fileName is an empty string ("").</exception>
        public DesignerPane(string fileName, IVsTextLines textBuffer)
        {
            if (textBuffer == null)
            {
                throw new ArgumentNullException("textBuffer");
            }

            // This call is required by the Windows.Forms Form Designer

            PrivateInit(fileName, textBuffer);
        }

        /// <summary>
        /// Private method used to initialize the instance of EditorPane.
        /// Captures the TextBuffer and the file name locally.
        /// </summary>
        /// <param name="fileName">An absolute path for the file that will be edited.</param>
        /// <param name="textBuffer">The reference to the instance of TextBuffer object.</param>
        private void PrivateInit(string fileName, IVsTextLines textBuffer)
        {
            updatingOnTextBufferLineChange = false;
            updatingOnUserEdit = false;
            gettingCheckoutStatus = false;
            textLines = textBuffer;
            this.fileName = fileName;

        }


        private void InitializeDesigner()
        {
            UmcDesignSurfaceManager surfaceManager = new UmcDesignSurfaceManager(vsServiceProvider);
            designSurface = surfaceManager.CreateDesignSurface() as UmcDesignSurface;
            Debug.Assert(designSurface != null);

            designSurface.OnUpdateCode += new UmcDesignSurface.UpdateCode(designSurface_OnUpdateCode);

            Control control = designSurface.View as Control;
            control.Parent = this;
            control.Dock = DockStyle.Fill;


            //after initial the design surface we can update designerview in the first time.
            string text = File.ReadAllText(this.fileName);
            //initial the design view from the file
            this.designSurface.UpdateDesignerView(text);
        }

        private void InitializeToolbox()
        {
            // !!!NOTE!!!:Below codes can be the sample when we involve Rascle controls so I did not delete them.
            // Please do remember to remove them when they are no longer needed.

            // Create the data object that will store the data for the menu item.
            //toolboxData = new OleDataObject();
            //toolboxData.SetData(typeof(TextBox), new TextBox());

            //// Get the toolbox service
            //IVsToolbox toolbox = (IVsToolbox)vsServiceProvider.GetService(typeof(SVsToolbox));

            //// Create the array of TBXITEMINFO structures to describe the items
            //// we are adding to the toolbox.
            //TBXITEMINFO[] itemInfo = new TBXITEMINFO[1];
            //itemInfo[0].bstrText = "Toolbox Sample Item";
            //itemInfo[0].hBmp = IntPtr.Zero;
            //itemInfo[0].dwFlags = (uint)__TBXITEMINFOFLAGS.TBXIF_DONTPERSIST;

            //ErrorHandler.ThrowOnFailure(toolbox.AddItem((IOleDataObject)toolboxData, itemInfo, "Toolbox Test")); 
        }

        #endregion

        #region Methods
        /// <summary>
        /// Subscribes to or unsubscribes from IVsTextLinesEvents events of the TextBuffer object.
        /// Registers our independent view with the IVsTextManager.
        /// </summary>
        /// <param name="subscribe">Indicates whether to Advise or to Unadvise from events.</param>
        private void AdviseTextLinesEvents(bool subscribe)
        {
            IConnectionPointContainer conPtCont = (IConnectionPointContainer)textLines;

            if (conPtCont != null)
            {
                IConnectionPoint conPt;
                Guid iidConPt = typeof(IVsTextLinesEvents).GUID;
                conPtCont.FindConnectionPoint(ref iidConPt, out conPt);
                
                if (subscribe)
                {
                    conPt.Advise((IVsTextLinesEvents)this, out cookie);
                }
                else
                {
                    // If the goal is to unsubscribe, but there is no subscription active, exit.
                    if (cookie == VSConstants.VSCOOKIE_NIL)
                    {
                        return;
                    }
                    conPt.Unadvise(cookie);
                    cookie = VSConstants.VSCOOKIE_NIL;
                }
            }

            // register our independent view with the IVsTextManager so that it knows
            // the user is working with a view over the text buffer. this will trigger
            // the text buffer to prompt the user whether to reload the file if it is
            // edited outside of the development Environment.
            IVsTextManager textManager = (IVsTextManager)GetVSService(typeof(SVsTextManager));

            if (textManager != null)
            {
                if (subscribe)
                {
                    textManager.RegisterIndependentView((IVsWindowPane)this, (IVsTextLines)textLines);
                }
                else
                {
                    textManager.UnregisterIndependentView((IVsWindowPane)this, (IVsTextLines)textLines);
                }
            }
        }

        /// <summary>
        /// This function asks to the QueryEditQuerySave service if it is possible to edit the file.
        /// </summary>
        /// <returns>False, if queued request to QueryEditQuerySave service, otherwise true.</returns>
        private bool CanEditFile()
        {
            // Check the status of the recursion guard
            if (gettingCheckoutStatus)
            {
                return false;
            }

            try
            {
                // Set the recursion guard
                gettingCheckoutStatus = true;

                // Get the QueryEditQuerySave service
                IVsQueryEditQuerySave2 queryEditQuerySave = (IVsQueryEditQuerySave2)GetVSService(typeof(SVsQueryEditQuerySave));

                // Now call the QueryEdit method to find the edit status of this file
                string[] documents = { this.fileName };
                uint result;
                uint outFlags;

                // Note that this function can popup a dialog to ask the user to checkout the file.
                // When this dialog is visible, it is possible to receive other request to change
                // the file and this is the reason for the recursion guard
                int hr = queryEditQuerySave.QueryEditFiles(
                    0,              // Flags
                    1,              // Number of elements in the array
                    documents,      // Files to edit
                    null,           // Input flags
                    null,           // Input array of VSQEQS_FILE_ATTRIBUTE_DATA
                    out result,     // result of the checkout
                    out outFlags    // Additional flags
                );
                if (ErrorHandler.Succeeded(hr) && (result == (uint)tagVSQueryEditResult.QER_EditOK))
                {
                    // In this case (and only in this case) we can return true from this function
                    return true;
                }
            }
            finally
            {
                gettingCheckoutStatus = false;
            }
            return false;
        }

        /// <summary>
        /// Returns the requested service from the Shell.
        /// </summary>
        /// <param name="serviceType">The System.Type of the service to retrieve. </param>
        /// <returns>An System.Object that implements the requested service, or null if the service cannot be retrieved.</returns>
        private object GetVSService(Type serviceType)
        {
            return vsServiceProvider.GetService(serviceType);
        }

        /// <summary>
        /// Handles the TextChanged event of contained RichTextBox object. 
        /// Process changes occurred inside the editor.
        /// </summary>
        /// <param name="sender">The reference to contained RichTextBox object.</param>
        /// <param name="e">The event arguments.</param>
        private void OnTextChange(object sender, EventArgs e)
        {
            // During the load operation the text of the control will change, but
            // this change must not be stored in the status of the document.
            if (!updatingOnTextBufferLineChange)
            {
                // The only interesting case is when we are changing the document
                // for the first time
                if (!isDirty)
                {
                    // Check if the QueryEditQuerySave service allow us to change the file
                    if (!CanEditFile())
                    {
                        // We can not change the file (e.g. a checkout operation failed),
                        // so undo the change and exit.
                        //editorControl.Undo();
                        return;
                    }

                    // It is possible to change the file, so update the status.
                    isDirty = true;
                }
                try
                {
                    updatingOnUserEdit = true;
                    //SetText(editorControl.Text);
                }
                finally
                {
                    updatingOnUserEdit = false;
                }
            }
        }

        void EditorPane_DragEnter(object sender, DragEventArgs e)
        {
            Logger.Output("EditorPane_DragEnter");
            // Check if the source of the drag is the toolbox item
            // created by this sample.
            if (e.Data.GetDataPresent(typeof(TextBox)))
            {
                // Only in this case we will enable the drop
                e.Effect = DragDropEffects.Copy;
            }
        }

        void EditorPane_DragDrop(object sender, DragEventArgs e)
        {
            Logger.Output("EditorPane_DragDrop");
            e.Effect = DragDropEffects.None;
            //System.Diagnostics.Debug.Assert(false, "Breakpoint");
            // The only drop allow is from the toolbox item
            if (e.Data.GetDataPresent(typeof(TextBox)))
            {
                TextBox data = (TextBox)e.Data.GetData(typeof(TextBox));
                e.Effect = DragDropEffects.Copy;
            }
        }

        /// <summary> 
        /// Let this control to process the mnemonics.
        /// </summary>
        /// <param name="charCode">System.Char value of a processable character.</param>
        /// <returns>True, if specified characted was processed successfully, otherwise false.</returns>
        [EnvironmentPermission(SecurityAction.LinkDemand, Unrestricted = true)]
        protected override bool ProcessDialogChar(char charCode)
        {
            // If we're the top-level form or control, we need to do the mnemonic handling
            if (charCode != ' ' && ProcessMnemonic(charCode))
            {
                return true;
            }
            return base.ProcessDialogChar(charCode);
        }

        /// <summary>
        /// This is a helper routine to replace the contents of the Text Buffer with given text.
        /// This function handles the interop of passing the string as a block of memory via an IntPtr. 
        /// It uses a CoTaskMemAlloc to allocate a block of memory at a fixed location.
        /// </summary>
        /// <remarks>Throws an exception if unmanaged operations fail.</remarks>
        /// <param name="newText">The string value that assigns the TextBuffer.</param>
        [EnvironmentPermissionAttribute(SecurityAction.LinkDemand, Unrestricted = true)]
        private void SetText(string newText)
        {
            int endLine, endCol;
            ErrorHandler.ThrowOnFailure(textLines.GetLastLineIndex(out endLine, out endCol));
            int len = (newText == null) ? 0 : newText.Length;
            IntPtr pText = Marshal.StringToCoTaskMemAuto(newText);
            
            try
            {
                ErrorHandler.ThrowOnFailure(textLines.ReplaceLines(0, 0, endLine, endCol, pText, len, null));
            }
            finally
            {
                Marshal.FreeCoTaskMem(pText);
            }
        }

        /// <summary>
        /// Function to return the string to be used in the "Find What" field of the find window. 
        /// </summary>
        /// <param name="pvar">the string to be returned.</param>
        /// <remarks>Will return null if no text is selected or if there are multiple lines of text selected.</remarks>
        private void GetInitialSearchString(out object pvar)
        {
            pvar = null;
            // If no text is selected, return null
            //if (0 == editorControl.SelectionLength)
            //{
            //    pvar = null;
            //    return;
            //}

            //// Now check if multiple lines have been selected
            //int endIndex = editorControl.SelectionStart + editorControl.SelectionLength;
            //int endline = editorControl.GetLineFromCharIndex(endIndex);
            //int startline = editorControl.GetLineFromCharIndex(editorControl.SelectionStart);
            //if (startline != endline)
            //{
            //    pvar = null;
            //    return;
            //}

            //pvar = editorControl.SelectedText;
        }

        void designSurface_OnUpdateCode(string code)
        {
            updatingOnUserEdit = true;      //prevent the OnChangeLineText from triggering

            int lineCount;
            ErrorHandler.ThrowOnFailure(this.textLines.GetLineCount(out lineCount));
            Logger.Output("Total line count in current IVsTextLines:" + lineCount);
            if (lineCount <= 0)
            {
                return;
            }

            int lastLineSize;
            ErrorHandler.ThrowOnFailure(this.textLines.GetLengthOfLine(lineCount - 1, out lastLineSize));
            Logger.Output("Size of the last line:" + lastLineSize);

            IntPtr pszText = Marshal.StringToHGlobalAuto(code);
            TextSpan[] pChangedSpan = new TextSpan[code.Length];
            int ret = this.textLines.ReplaceLines(0, 0, lineCount - 1, lastLineSize, pszText, code.Length, pChangedSpan);
            Marshal.FreeHGlobal(pszText);
            ErrorHandler.ThrowOnFailure(ret);

            updatingOnUserEdit = false;     //not prevent the OnChangeLineText from triggering
        }

        #region IDisposable Pattern
        /// <summary> 
        /// Cleans up used resources.
        /// </summary>
        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                if (textLines != null)
                {
                    AdviseTextLinesEvents(false);
                    textLines = null;
                }
                if (components != null)
                {
                    components.Dispose();
                }
                if (designSurface != null)
                {
                    designSurface.Dispose();
                }
                GC.SuppressFinalize(this);
            }
            base.Dispose(disposing);
        }
        #endregion

        #region IOleCommandTarget Members

        /// <summary>
        /// The shell call this function to know if a menu item should be visible and
        /// if it should be enabled/disabled.
        /// Note that this function will only be called when an instance of this editor is open.
        /// </summary>
        /// <param name="pguidCmdGroup">Guid describing which set of command the current command(s) belong to.</param>
        /// <param name="cCmds">Number of command which status are being asked for.</param>
        /// <param name="prgCmds">Information for each command.</param>
        /// <param name="pCmdText">Used to dynamically change the command text.</param>
        /// <returns>S_OK if the method succeeds.</returns> 
        public int QueryStatus(ref Guid pguidCmdGroup, uint cCmds, OLECMD[] prgCmds, IntPtr pCmdText)
        {
            // validate parameters
            if (prgCmds == null || cCmds != 1)
            {
                return VSConstants.E_INVALIDARG;
            }

            OLECMDF cmdf = OLECMDF.OLECMDF_SUPPORTED;

            if (pguidCmdGroup == VSConstants.GUID_VSStandardCommandSet97)
            {
                // Process standard Commands
                switch (prgCmds[0].cmdID)
                {
                    case (uint)VSConstants.VSStd97CmdID.SelectAll:
                        {
                            // Always enabled
                            cmdf = OLECMDF.OLECMDF_SUPPORTED | OLECMDF.OLECMDF_ENABLED;
                            break;
                        }
                    case (uint)VSConstants.VSStd97CmdID.Copy:
                    case (uint)VSConstants.VSStd97CmdID.Cut:
                        {
                            // Enable if something is selected
                            //if (editorControl.SelectionLength > 0)
                            //{
                            //    cmdf |= OLECMDF.OLECMDF_ENABLED;
                            //}
                            break;
                        }
                    case (uint)VSConstants.VSStd97CmdID.Paste:
                        {
                            // Enable if clipboard has content we can paste

                            //if (editorControl.CanPaste(DataFormats.GetFormat(DataFormats.Text)))
                            //{
                            //    cmdf |= OLECMDF.OLECMDF_ENABLED;
                            //}
                            break;
                        }
                    case (uint)VSConstants.VSStd97CmdID.Redo:
                        {
                            // Enable if actions that have occurred within the RichTextBox 
                            // can be reapplied
                            //if (editorControl.CanRedo)
                            //{
                            //    cmdf |= OLECMDF.OLECMDF_ENABLED;
                            //}
                            break;
                        }
                    case (uint)VSConstants.VSStd97CmdID.Undo:
                        {
                            //if (editorControl.CanUndo)
                            //{
                            //    cmdf |= OLECMDF.OLECMDF_ENABLED;
                            //}
                            break;
                        }
                    case (uint)VSConstants.VSStd97CmdID.NewWindow:
                        {
                            cmdf |= OLECMDF.OLECMDF_ENABLED;
                            break;
                        }
                    default:
                        return (int)(Constants.OLECMDERR_E_NOTSUPPORTED);
                }
            }
            else if (pguidCmdGroup == GuidList.guidAppExpCmdSet)
            {
                // Process our Commands
                switch (prgCmds[0].cmdID)
                {
                    // if we had commands specific to our editor, they would be processed here
                    default:
                        return (int)(Constants.OLECMDERR_E_NOTSUPPORTED);
                }
            }
            else
                return (int)(Constants.OLECMDERR_E_NOTSUPPORTED); ;

            prgCmds[0].cmdf = (uint)cmdf;

            return VSConstants.S_OK;
            
        }

        /// <summary>
        /// Execute a specified command.
        /// </summary>
        /// <param name="pguidCmdGroup">Guid describing which set of command the current command(s) belong to.</param>
        /// <param name="nCmdID">Command that should be executed.</param>
        /// <param name="nCmdexecopt">Options for the command.</param>
        /// <param name="pvaIn">Pointer to input arguments.</param>
        /// <param name="pvaOut">Pointer to command output.</param>
        /// <returns>S_OK if the method succeeds or OLECMDERR_E_NOTSUPPORTED on unsupported command.</returns> 
        /// <remarks>Typically, only the first 2 arguments are used (to identify which command should be run).</remarks>
        public int Exec(ref Guid pguidCmdGroup, uint nCmdID, uint nCmdexecopt, IntPtr pvaIn, IntPtr pvaOut)
        {
            Trace.WriteLine(string.Format(CultureInfo.CurrentCulture, "Entering Exec() of: {0}", this.ToString()));

            if (pguidCmdGroup == VSConstants.GUID_VSStandardCommandSet97)
            {
                // Process standard Visual Studio Commands
                switch (nCmdID)
                {
                    case (uint)VSConstants.VSStd97CmdID.Copy:
                        {
                            //editorControl.Copy();
                            break;
                        }
                    case (uint)VSConstants.VSStd97CmdID.Cut:
                        {
                            //editorControl.Cut();
                            break;
                        }
                    case (uint)VSConstants.VSStd97CmdID.Paste:
                        {
                            //editorControl.Paste();
                            break;
                        }
                    case (uint)VSConstants.VSStd97CmdID.Redo:
                        {
                            //editorControl.Redo();
                            break;
                        }
                    case (uint)VSConstants.VSStd97CmdID.Undo:
                        {
                            //editorControl.Undo();
                            break;
                        }
                    case (uint)VSConstants.VSStd97CmdID.SelectAll:
                        {
                            //editorControl.SelectAll();
                            break;
                        }
                    case (uint)VSConstants.VSStd97CmdID.NewWindow:
                        {
                            int hr = VSConstants.S_OK;

                            IVsUIShellOpenDocument uishellOpenDocument = (IVsUIShellOpenDocument)GetVSService(typeof(SVsUIShellOpenDocument));
                            if (uishellOpenDocument != null)
                            {
                                IVsWindowFrame windowFrameOrig = (IVsWindowFrame)GetVSService(typeof(SVsWindowFrame));
                                if (windowFrameOrig != null)
                                {
                                    IVsWindowFrame windowFrameNew;
                                    Guid logViewPrimary = VSConstants.LOGVIEWID_Primary;
                                    hr = uishellOpenDocument.OpenCopyOfStandardEditor(windowFrameOrig, ref logViewPrimary, out windowFrameNew);
                                    if (windowFrameNew != null)
                                    {
                                        hr = windowFrameNew.Show();
                                    }
                                    ErrorHandler.ThrowOnFailure(hr);
                                }
                            }
                            break;
                        }
                    default:
                        return (int)(Constants.OLECMDERR_E_NOTSUPPORTED);
                }
            }
            else if (pguidCmdGroup == GuidList.guidAppExpCmdSet)
            {
                switch (nCmdID)
                {
                    // if we had commands specific to our editor, they would be processed here
                    default:
                        return (int)(Constants.OLECMDERR_E_NOTSUPPORTED);
                }
            }
            else
                return (int)Constants.OLECMDERR_E_UNKNOWNGROUP;

            return VSConstants.S_OK;
        }
        #endregion IOleCommandTarget

        #region IVsDeferredDocView Members

        /// <summary>
        /// Assigns out parameter with the Guid of the EditorFactory.
        /// </summary>
        /// <param name="pGuidCmdId">[out] The value of the Guid of the EditorFactory.</param>
        /// <returns>S_OK if Marshal operations completed successfully.</returns>
        public int get_CmdUIGuid(out Guid pGuidCmdId)
        {
            pGuidCmdId = GuidList.guidUmcDesignerEditorFactory;
            return VSConstants.S_OK;
        }

        /// <summary>
        /// Assigns out parameter with the document view being implemented.
        /// </summary>
        /// <param name="ppUnkDocView">[out] The IntPtr object that references to current view.</param>
        /// <returns>S_OK if Marshal operations completed successfully.</returns>
        [EnvironmentPermission(SecurityAction.Demand)]
        public int get_DocView(out IntPtr ppUnkDocView)
        {
            ppUnkDocView = Marshal.GetIUnknownForObject(this);
            return VSConstants.S_OK;
        }

        #endregion

        #region IVsTextLinesEvents Members

        /// <summary>
        /// Notifies the client when the text line attributes have been changed.
        /// </summary>
        /// <param name="iFirstLine">First affected line, inclusive.</param>
        /// <param name="iLastLine">Last affected line, inclusive.</param>
        public void OnChangeLineAttributes(int iFirstLine, int iLastLine)
        {
            // don't care about line color changes in our custom editor view.
        }
        /// <summary>
        /// Notifies the client when the content of a text line in the buffer has changed.
        /// </summary>
        /// <param name="pTextLineChange">Pointer to the TextLineChange structure that defines the shape of the old and new text.</param>
        /// <param name="fLast">Obsolete. Do not use.</param>
        public void OnChangeLineText(TextLineChange[] pTextLineChange, int fLast)
        {
            // We don't need to update the textBox control if this is a change to 
            // the TextBuffer caused by our own user edit.

            if (!updatingOnUserEdit)
            {
                try
                {
                    int cLines;
                    int cLineLen;
                    string text;
                    updatingOnTextBufferLineChange = true;
                    textLines.GetLineCount(out cLines);
                    textLines.GetLengthOfLine(cLines - 1, out cLineLen);
                    textLines.GetLineText(0, 0, cLines - 1, cLineLen, out text);

                    this.designSurface.UpdateDesignerView(text);
                }
                catch(Exception ex)
                {
                    Logger.Output(string.Format("Error({0}):{1}", ex.GetType().FullName, ex.Message),WriteTo.OutputWindow);
                }
                finally
                {
                    updatingOnTextBufferLineChange = false;
                }
            }
        }

        #endregion
        
        #region IVsWindowPane Members
        /// <summary>
        /// Initializes a new window pane.
        /// Additionally initialize internal VS shell service provider instance.
        /// </summary>
        /// <param name="psp">Pointer to the object which realize IServiceProvider interface.</param>
        /// <returns>S_OK if the method succeeds.</returns>
        public int SetSite(IOleServiceProvider psp)
        {
            vsServiceProvider = new ServiceProvider(psp);
            InitializeToolbox();
            InitializeDesigner();
            return VSConstants.S_OK;
        }
        /// <summary>
        /// Handles the translation of special navigation keys.
        /// </summary>
        /// <param name="lpmsg">Keyboard character or character combination to be handled.</param>
        /// <returns>S_OK if the method succeeds.</returns> 
        public int TranslateAccelerator(MSG[] lpmsg)
        {
            return VSConstants.S_FALSE;
        }
        /// <summary>
        /// Saves a view state of a document window. 
        /// </summary>
        /// <param name="pStream">Pointer to the IStream interface of the view state to save.</param>
        /// <returns>S_OK if the method succeeds.</returns> 
        public int SaveViewState(IStream pStream)
        {
            return VSConstants.S_OK;
        }
        /// <summary>
        /// Loads a view state.
        /// </summary>
        /// <param name="pStream">Pointer to the IStream interface of the view state to load.</param>
        /// <returns>S_OK if the method succeeds.</returns> 
        public int LoadViewState(IStream pStream)
        {
            return VSConstants.S_OK;
        }

        /// <summary>
        /// Gets the default size of a given window pane.
        /// </summary>
        /// <param name="pSize">The size of a given window pane.</param>
        /// <returns>S_OK if the method succeeds.</returns> 
        public int GetDefaultSize(SIZE[] pSize)
        {
            if (pSize != null && pSize.Length >= 1)
            {
                pSize[0].cx = Size.Width;
                pSize[0].cy = Size.Height;
            }

            return VSConstants.S_OK;
        }

        /// <summary>
        /// Creates a window pane.
        /// </summary>
        /// <param name="hwndParent">Handle to the parent window.</param>
        /// <param name="x">Absolute x ordinate.</param>
        /// <param name="y">Absolute y ordinate.</param>
        /// <param name="cx">x ordinate relative to x.</param>
        /// <param name="cy">y ordinate relative to y.</param>
        /// <param name="hwnd">[out] Pointer to a handle to the new window pane.</param>
        /// <returns>S_OK if the method succeeds.</returns> 
        public int CreatePaneWindow(IntPtr hwndParent, int x, int y, int cx, int cy, out IntPtr hwnd)
        {
            int cLines;
            int cLineLen;
            string text;

            AdviseTextLinesEvents(true);

            textLines.GetLineCount(out cLines);
            textLines.GetLengthOfLine(cLines - 1, out cLineLen);
            textLines.GetLineText(0, 0, cLines - 1, cLineLen, out text);
            //editorControl.Text = text;

            Win32Methods.SetParent(Handle, hwndParent);
            hwnd = Handle;
            Size = new Size(cx - x, cy - y);

            return VSConstants.S_OK;
        }

        /// <summary>
        /// Closes a window pane with Dispose call.
        /// </summary>
        /// <returns>S_OK if the method succeeds.</returns>
        public int ClosePane()
        {
            this.Dispose(true);
            return VSConstants.S_OK;
        }

        #endregion        
        
        #region IVsToolboxUser Members

        public int IsSupported(Microsoft.VisualStudio.OLE.Interop.IDataObject pDO)
        {
            //// Create a OleDataObject from the input interface.
            //OleDataObject oleData = new OleDataObject(pDO);


            //// Check if the data object is of type MyToolboxData.
            //if (oleData.GetDataPresent(typeof(System.Windows.Forms.Button)))
            //    return VSConstants.S_OK;


            //// In all the other cases return S_FALSE
            //return VSConstants.S_FALSE;

            return VSConstants.S_OK;
            

        }

        public int ItemPicked(Microsoft.VisualStudio.OLE.Interop.IDataObject pDO)
        {
            return VSConstants.S_OK;
        }

        #endregion


        #endregion Methods
    }
}
